#pragma once
#include <map>
#include <set>
#include <memory>
#include <utility>
#include <functional>
#include <unordered_map>
#include <fcntl.h>
#include "sock.hpp"
#include "epoll_operator.hpp"
class IO;
class epollSock;
using fun_c = std::function<void(epoll_event *, int, int, std::unordered_map<int, IO *> &)>;
void handlevent(epoll_event *event, int num, int sock, std::unordered_map<int, IO *> &ptr);
class IO
{
public:
    int _sock;              // 套接字
    std::string _inbuffer;  // 读缓冲区
    std::string _outbuffer; // 写缓冲区
    Sock *p;                // 服务器
    EpollOper *ep;          // epoll操作
    epollSock *esp;         // epoll服务器
};
class epollSock
{
public:
    epollSock() : _handl(handlevent)
    {
        memset(_event, 0, _event_num);
        _sever.Bind();
        int sock = _sever.Listen();
        // 创建映射关系
        IO *s = new IO;
        s->p = &_sever;
        s->ep = &_epoll;
        s->esp = this;
        s->_sock = sock;
        _sock = sock;
        std::pair<int, IO *> op(_sock, s);
        _sockIo.emplace(op);
        // 向epoll中添加节点,ET模式
        _epoll.EpollCtl(EPOLL_CTL_ADD, sock, EPOLLIN | EPOLLET);
    }
    void Change(int sock,bool button)
    {
        if(button)
            _epoll.EpollCtl(EPOLL_CTL_MOD, sock, EPOLLIN | EPOLLOUT | EPOLLET);
        else
            _epoll.EpollCtl(EPOLL_CTL_MOD, sock, EPOLLIN | EPOLLET);
    }
    void Start()
    {
        while (true)
        {
            int n = _epoll.EpollWit(_event, _event_num, 1000);
            switch (n)
            {
            case -1:
                std::cout << "epoll_wait fail:" << strerror(errno) << std::endl;
                break;
            case 0:
                std::cout << "timeout ..." << std::endl;
                break;
            default:
                _handl(_event, n, _sock, _sockIo);
                break;
            }
        }
    }

private:
    int _sock;
    Sock _sever;                       // listensock套接字
    EpollOper _epoll;                  // epoll
    fun_c _handl;                      // 处理就绪事件
    const static int _event_num = 256; // 存储就绪数组大小
    epoll_event _event[_event_num];    // 存储就绪事件
public:
    std::unordered_map<int, IO *> _sockIo; // 套接字所对应的数组
};
